//
//  ViewController.m
//  JKRuntimeAPITest
//
//  Created by 王冲 on 2018/10/9.
//  Copyright © 2018年 JK科技有限公司. All rights reserved.
//

#import "ViewController.h"
#import <objc/runtime.h>
#import "JKPerson.h"
#import "JKStudent.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
   
    self.view.backgroundColor = [UIColor purpleColor];
    
    // 1.查看一个类的isa指向问题
    //[self classISA];
    // 2.动态的创建一个类
    //[self classISA];
    // 3.新类的使用
    // [self newClassUse];
    // 4.API-成员变量
    [self memberVariables];
}

#pragma mark 4.API-成员变量
-(void)memberVariables{
    
    // 1.获取成员变量信息
    Ivar nameIvar = class_getInstanceVariable([JKPerson class], "_name");
    //NSLog(@"%s %s",ivar_getName(nameIvar),ivar_getTypeEncoding(nameIvar));
    
    // 2.设置和获取成员变量的值
    JKPerson *person = [[JKPerson alloc]init];
    object_setIvar(person,nameIvar, @"JK");
    object_getIvar(person, nameIvar);
    //NSLog(@"%@  %@",person.name,object_getIvar(person, nameIvar));
    
    // 3.成员变量的数量
    unsigned int count;
    Ivar *ivars = class_copyIvarList([JKPerson class], &count);
    for (int i = 0; i < count; i++) {
        // 取出i位置的成员变量
        Ivar ivar = ivars[i];
        NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
    }
    free(ivars);
    
    
    
}

#pragma mark 3.新类的使用
-(void)newClassUse{
    
    // 1.创建新的类
    /**
     三个参数：
     Class  _Nullable __unsafe_unretained superclass: 父类
     const char * _Nonnull name: 新的类名字
     size_t extraBytes: 需不需要为这个类增加额外的内存空间
     */
    Class newClass = objc_allocateClassPair([NSObject class], "JKCat", 0);
    
    // 在1与2之间可以做一些其他的操作：如：添加属性、方法。。。。。。
    // 1.1 添加成员变量（类一旦创建就不能再创建成员变量）
    /**
     Class  _Nullable __unsafe_unretained cls : 创建的新类
     const char * _Nonnull name : 成员变量的名字
     size_t size: 占用多少个字节
     uint8_t alignment: 对其,写 1 就好
     const char * _Nullable types: 类型
     */
    class_addIvar(newClass,"age", 4, 1, @encode(int));
    
    
    // 1.2、增加一个方法
    /**
      @param cls 将要添加方法的类, 可以传 [类名 class]
      @param name 将要添加的方法名, 传的类型为 @selector(方法名).
      @param imp 实现这个方法的函数, 传的类型 (1) C语言写法: (IMP) 方法名; (2) OC写法: class_getMethodImplementation(self, @selector(方法名))
      @param types 添加方法的返回值和参数数组
      特别说明：[self class] 是指：run 这个方法我写在了这个类里面，要是其他类把self换了就好
      "v@:"：v表示是添加方法无返回值,@表示是id(也就是要添加的类); ：表示添加的方法类型
    */
    class_addMethod(newClass, @selector(run), class_getMethodImplementation([self class], @selector(run)),"V@:");
    
    // 2.注册新的类
    objc_registerClassPair(newClass);
    
    id object = [[newClass alloc]init];
    [object setValue:@12 forKey:@"age"];
    
    NSLog(@"age = %@",[object valueForKey:@"age"]);
    
    [object run];
    
    // 3.销毁一个类
    //objc_disposeClassPair(newClass);
    
    
}


-(void)run{
    
    NSLog(@"=====run=====");
}


#pragma mark 2.动态的创建一个类
-(void)creatClass{
   
    // 1.创建新的类
    /**
        三个参数：
        Class  _Nullable __unsafe_unretained superclass: 父类
        const char * _Nonnull name: 新的类名字
        size_t extraBytes: 需不需要为这个类增加额外的内存空间
     */
    Class newClass = objc_allocateClassPair([NSObject class], "JKCat", 0);
    
    // 在1与2之间可以做一些其他的操作：如：添加属性、方法。。。。。。
    // 1.1
    
    
    // 2.注册新的类
    objc_registerClassPair(newClass);
    
    // 3.销毁一个类
    objc_disposeClassPair(newClass);
    
    
}

#pragma mark 1.查看一个类的isa指向问题
-(void)classISA{
    
    JKPerson *person = [[JKPerson alloc]init];
    
    // 获取isa指向的Class
    NSLog(@"%p %p %p", object_getClass([JKPerson class]), [JKPerson class],[JKPerson new]);
    
    // 设置isa指向的Class
    object_setClass(person, [JKStudent class]);
    [person eat];
    
    // 判断一个OC对象是否为 Class(类)
    NSLog(@"%d %d %d",object_isClass(person),object_isClass([JKPerson class]),object_isClass(object_getClass([JKPerson class])));
    
    // 判断一个OC对象是否为 metaClass(元类)
    NSLog(@"%d %d",class_isMetaClass([JKPerson class]),class_isMetaClass(object_getClass([JKPerson class])));
    
    // 获取一个类的父类
    Class p = class_getSuperclass([JKPerson class]);
    NSLog(@"%@",p);    
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
